/**
 * JavaScript Common Templates(jCT) 3(第3版) 正则注释风格版
 * http://code.google.com/p/jsct/
 *
 * licensed under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Author achun (achun.shx at gmail.com)
 * Create Date: 2008-9-9
 * Last Date: 2008-9-11
 * Revision:rc3.8.9.11
 */
function jCT(txt,path){//构建jCT对象,仅仅准备基础数据
	this.Fn = new arguments.callee.Instance({txt:txt,path:path});
	for (var i in this) this.Fn.Reserve+=','+i+',';
}
jCT.prototype={
	Extend:function(jct){//扩展自己
		for (var i in jct){
			if(this[i] && this[i].Fn && this[i].Fn.JavaScriptCommonTemplates && this[i].Extend )
				this[i].Extend(jct[i]);
			else if(this.Fn.Reserve.indexOf(','+i+',')==-1)//防止保留成员被覆盖
				this[i]=jct[i];
		}
		if(typeof jct.RunNow=='function') jct.RunNow.call(this);
		return this;
	},
	ExecChilds:function(childs,exec){//执行childs对象所列成员里的某个方法，默认是Exec方法
		exec=exec||'Exec';
		for(var c in childs)
			if(this[c] && (typeof this[c][exec]=='function'))
				this[c][exec](childs[c]);
		return this;
	},
	BuildChilds:function(childs){//构建子jCT对象,并执行RunNow
		if(undefined==childs) childs=[];
		var cs={};
		for(var i=0;i<childs.length;i++) cs[childs[i]]=true;
		for (var i in this)
			if(this[i].Fn && this[i].Fn.JavaScriptCommonTemplates && (childs.length==0 || cs[i])){
				this[i].Build();
			}
		return this;
	},
	GetView:function(){return 'Invalid templates';},//得到装配数据后的视图，此方法会在Build的过程中重建
	Build:function(){//构建实例
		this.Fn.Build(this);
		return this;
	}
};
jCT.Instance=function(Options){
	this.Src=Options.txt||'';
	this.Src=this.Src.replace(this.RegClear,'');
	this.Path=Options.path||'';
	this.A=[];//由src转换的模板数组
	this.V=[];//GetView执行的文本结果,以数组形式存放
	this.EXEC=[];//生成的js代码的临时数组
};
jCT.Instance.prototype={
	JavaScriptCommonTemplates:3.0,
	Reserve:'',//保留成员
	RegClear:/<!--clear([\w\W]*?)\/clear-->/g,
	RegTrim:/^\s+|\s+$/g,
	RegFun:/\/\*((?:(?!\*\/).)+)\*\//,
	RegChild:/(<!---\/\*\+@)([\w\W]*?)(\*\/-->)/g,//子模板
	Reg:/(<!---|\+-)([\w\W]*?)(-->|-\+)/g,//comment风格的定义
	Push:function(pos,code,exp){
		if(pos>this.Pos){
			var htm=this.Src.slice(this.Pos,pos).replace(this.RegTrim,'');
			if(htm){
				this.EXEC.push('this.Fn.V.push(this.Fn.A['+this.A.length+']);');
				this.A.push(htm);
			}
		}
		if(code){
			code=code.replace(this.RegTrim,'');
			if(exp)
				this.EXEC.push('this.Fn.V.push('+code+');');
			else
				this.EXEC.push(code);
		}
	},
	Build:function(self){
		this.EXEC=['this.Fn.V=[];'];
		this.Pos=0;
		this.Reg.lastIndex=0;
		var arr;
		while(this.Pos<this.Src.length && (arr=this.Reg.exec(this.Src))!=null){
			this.Reg.lastIndex=this.Parse(arr[0],arr[1],arr[2],arr[3],arr.index,self);
		}
		this.Push(this.Src.length,'return this.Fn.V.join("");');//最后一段
		try{
			self.GetView=new Function(this.EXEC.join('\n'));
		}catch (ex){
			this.V=['jCT Parse Error'];
			self.ERROR={message:ex.message + '\n'+ (ex.lineNumber || ex.number)};
		}
		if(self.RunNow)
			self.RunNow();
	},
	Parse:function(all,begin,code,end,pos,self){
		if(begin=='+-'){
			this.Push(pos,code,true);
			this.Pos=pos+all.length;
		}else{
			//前部html存入
			this.Push(pos);
			var arr=this.RegFun.exec(code);
			if(arr && arr[1].slice(0,1)=='+'){//function(text,fun,at){//成员语法
				switch(arr[1].slice(1,2)){
				case '@'://子模板开始
					var name='<!---/'+'*-'+arr[1].slice(1)+'*'+'/-->';
					var at=this.Src.indexOf(name,pos+all.length);
					if(at>0){
						self[arr[1].slice(2)]=new jCT(this.Src.slice(pos+all.length,at),this.Path);
						this.Pos=at+name.length;
					}else{
						this.Pos=this.Src.length;
					}
					break;
				case '$'://成员对象
					var val=code.slice(arr.index+arr[0].length);
					var obj=new Function('return '+val+';');
					self[arr[1].slice(2).replace(this.RegTrim,'')]=obj.call(self);
					this.Pos=pos+all.length;
					break;
				default://成员函数
					self[arr[1].slice(1).replace(this.RegTrim,'')]=new Function(code.slice(arr.index+arr[0].length));
					this.Pos=pos+all.length;
					break;
				}
			}else{
				this.Push(-1,code);
				this.Pos=pos+all.length;
			}
		}
		return this.Pos;
	}
};